﻿using System;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace Ogdi.InteractiveSdk.WebForms
{
    public class XmlPlusContinuation
    {
        public XElement Xml { get; set; }
        public string NextPartitionKey { get; set; }
        public string NextRowKey { get; set; }
    }

    public class ServiceInterface
    {
        /// <summary>
        /// Get an XML element containing data from the specified table, filtering according
        /// to the filter criteria specified by the caller.
        /// </summary>
        /// <param name="tableName">Table name.</param>
        /// <param name="filter">Filter criteria, in Azure Table Services query syntax.</param>
        /// <returns>An XML element containing the results of the query.</returns>
        public static XmlPlusContinuation GetData(string container, string tableName,
                                                    string filter, int pageSize,
                                                    string nextPartitionKey, string nextRowKey)
        {
            var serviceUriBuilder = new StringBuilder();

            serviceUriBuilder.Append(RoleEnvironment.GetConfigurationSettingValue("serviceUri"));
            serviceUriBuilder.Append(container);
            serviceUriBuilder.Append("/");
            serviceUriBuilder.Append(tableName);
            serviceUriBuilder.Append("?$top=");
            serviceUriBuilder.Append(pageSize);

            if (!String.IsNullOrEmpty(filter))
            {
                serviceUriBuilder.Append("&$filter=");
                serviceUriBuilder.Append(filter);
            }

            if (!String.IsNullOrEmpty(nextPartitionKey) && !String.IsNullOrEmpty(nextRowKey))
            {
                serviceUriBuilder.Append("&NextPartitionKey=");
                serviceUriBuilder.Append(nextPartitionKey);
                serviceUriBuilder.Append("&NextRowKey=");
                serviceUriBuilder.Append(nextRowKey);
            }

            var webRequest = HttpWebRequest.Create(serviceUriBuilder.ToString());
            var response = webRequest.GetResponse();
            var responseStream = response.GetResponseStream();
            var xmlPlusContinuation = new XmlPlusContinuation();
            xmlPlusContinuation.NextPartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"];
            xmlPlusContinuation.NextRowKey = response.Headers["x-ms-continuation-NextRowKey"];

            var feed = XElement.Load(XmlReader.Create(responseStream));

            var propertiesElements = feed.Elements(Constants.nsAtom + "entry").Elements(Constants.nsAtom + "content").Elements(Constants.nsm + "properties");
            // Remove PartitionKey, RowKey, and Timestamp because we don't want users to focus on these.
            // They are required by Azure Table storage, but will most likely go away
            // when we move to SDS.
            propertiesElements.Elements(Constants.nsd + "PartitionKey").Remove();
            propertiesElements.Elements(Constants.nsd + "RowKey").Remove();
            propertiesElements.Elements(Constants.nsd + "Timestamp").Remove();

            // XmlDataSource doesn't support namespaces well
            // http://www.hanselman.com/blog/PermaLink,guid,8147b263-24fc-498d-83d1-546f4dde3fc3.aspx
            // Therefore, we will return XML that doesn't have any
            xmlPlusContinuation.Xml = new XElement("Root", propertiesElements);
            xmlPlusContinuation.Xml.Add(new XAttribute("tableName", tableName));
            StripNamespaces(xmlPlusContinuation.Xml);

            return xmlPlusContinuation;
        }


        /// <summary>
        /// DAISY Plugin -  This method will return complete data for selected entitySet. 
        /// Get an XML element containing data from the specified table, filtering according
        /// to the filter criteria specified by the caller.
        /// </summary>
        /// <param name="tableName">Table name.</param>
        /// <param name="filter">Filter criteria, in Azure Table Services query syntax.</param>
        /// <returns>An XML element containing the results of the query.</returns>
        public static XmlPlusContinuation GetDaisyData(string container, string tableName,
                                                   string filter,
                                                   string nextPartitionKey, string nextRowKey)
        {
            var serviceUriBuilder = new StringBuilder();

            serviceUriBuilder.Append(RoleEnvironment.GetConfigurationSettingValue("serviceUri"));
            serviceUriBuilder.Append(container);
            serviceUriBuilder.Append("/");
            serviceUriBuilder.Append(tableName);

            if (!String.IsNullOrEmpty(filter))
            {
                serviceUriBuilder.Append("?$filter=");
                serviceUriBuilder.Append(filter);
            }

            if (!String.IsNullOrEmpty(nextPartitionKey) && !String.IsNullOrEmpty(nextRowKey))
            {
                serviceUriBuilder.Append("&NextPartitionKey=");
                serviceUriBuilder.Append(nextPartitionKey);
                serviceUriBuilder.Append("&NextRowKey=");
                serviceUriBuilder.Append(nextRowKey);
            }

            var webRequest = HttpWebRequest.Create(serviceUriBuilder.ToString());
            var response = webRequest.GetResponse();
            var responseStream = response.GetResponseStream();
            var xmlPlusContinuation = new XmlPlusContinuation();
            xmlPlusContinuation.NextPartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"];
            xmlPlusContinuation.NextRowKey = response.Headers["x-ms-continuation-NextRowKey"];

            var feed = XElement.Load(XmlReader.Create(responseStream));

            var propertiesElements = feed.Elements(Constants.nsAtom + "entry").Elements(Constants.nsAtom + "content").Elements(Constants.nsm + "properties");
            // Remove PartitionKey, RowKey, and Timestamp because we don't want users to focus on these.
            // They are required by Azure Table storage, but will most likely go away
            // when we move to SDS.
            propertiesElements.Elements(Constants.nsd + "PartitionKey").Remove();
            propertiesElements.Elements(Constants.nsd + "RowKey").Remove();
            propertiesElements.Elements(Constants.nsd + "Timestamp").Remove();

            // XmlDataSource doesn't support namespaces well
            // http://www.hanselman.com/blog/PermaLink,guid,8147b263-24fc-498d-83d1-546f4dde3fc3.aspx
            // Therefore, we will return XML that doesn't have any
            xmlPlusContinuation.Xml = new XElement("Root", propertiesElements);
            xmlPlusContinuation.Xml.Add(new XAttribute("tableName", tableName));
            StripNamespaces(xmlPlusContinuation.Xml);

            return xmlPlusContinuation;
        }

        /// <summary>
        /// Get an XML element containing all of the data from the specified data.
        /// </summary>
        /// <param name="tableName">Table name.</param>
        /// <returns>An XML element containing all of the data in the specified table.</returns>
        /// <remarks>Use this method with care, as it could potentially return a very large data set.
        /// In most cases, the caller should specify a filter criteria.</remarks>
        public static XmlPlusContinuation GetData(string container, string tableName, int pageSize)
        {
            return GetData(container, tableName, null, pageSize, null, null);
        }

        /// <summary>
        /// Strip namespaces from a hierarchy of XML elements.
        /// </summary>
        /// <param name="root">XML element.</param>
        /// <returns>Same as <paramref>root</paramref> parameter.</returns>
        private static XElement StripNamespaces(XElement root)
        {
            // found this code at http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/bed57335-827a-4731-b6da-a7636ac29f21/
            foreach (XElement e in root.DescendantsAndSelf())
            {
                if (e.Name.Namespace != XNamespace.None)
                {
                    e.Name = XNamespace.None.GetName(e.Name.LocalName);
                }
                if (e.Attributes().Where(a => a.IsNamespaceDeclaration || a.Name.Namespace != XNamespace.None).Any())
                {
                    e.ReplaceAttributes(e.Attributes().Select(a => a.IsNamespaceDeclaration ? null : a.Name.Namespace != XNamespace.None ? new XAttribute(XNamespace.None.GetName(a.Name.LocalName), a.Value) : a));
                }
            }

            return root;
        }
    }
}
